"""
高级计算器图形界面模块
提供完整的GUI界面和用户交互功能
"""
import tkinter as tk
from tkinter import ttk, messagebox
from typing import Optional, Callable
import math

from calculator_core import Calculator, ScientificCalculator
from memory_manager import MemoryManager
from history_manager import HistoryManager, HistoryEntry


class CalculatorGUI:
    """高级计算器图形界面类"""
    
    def __init__(self, root: tk.Tk):
        """
        初始化GUI界面
        
        Args:
            root: Tkinter根窗口
        """
        self.root = root
        self.root.title("高级计算器")
        self.root.geometry("500x700")
        self.root.resizable(False, False)
        
        # 设置主题样式
        style = ttk.Style()
        style.theme_use('clam')
        
        # 创建组件实例
        self.calc = ScientificCalculator()
        self.memory_manager = MemoryManager()
        self.history_manager = HistoryManager(max_entries=50)
        
        # GUI变量
        self.display_var = tk.StringVar()
        self.display_var.set("0")
        self.expression = ""
        self.is_new_number = True
        
        # 设置回调函数
        self.memory_manager.set_callback(self._on_memory_change)
        self.history_manager.set_callback(self._on_history_change)
        
        # 创建界面组件
        self.create_widgets()
        
        # 绑定键盘事件
        self._bind_keyboard_events()
        
        # 界面组件引用
        self.history_listbox: Optional[tk.Listbox] = None
        self.memory_label: Optional[ttk.Label] = None
        self.display: Optional[tk.Entry] = None
    
    def create_widgets(self) -> None:
        """创建界面组件"""
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky="nsew")
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(0, weight=1)
        
        # 创建各个组件区域
        self._create_history_section(main_frame, 0)
        self._create_display_section(main_frame, 1)
        self._create_memory_section(main_frame, 2)
        self._create_button_section(main_frame, 3)
    
    def _create_history_section(self, parent: ttk.Frame, row: int) -> None:
        """创建历史记录区域"""
        history_frame = ttk.LabelFrame(parent, text="历史记录", padding="5")
        history_frame.grid(row=row, column=0, columnspan=5, sticky="ew", pady=(0, 10))
        history_frame.columnconfigure(0, weight=1)
        
        # 历史记录列表
        self.history_listbox = tk.Listbox(history_frame, height=3, font=("Arial", 10))
        self.history_listbox.grid(row=0, column=0, sticky="ew")
        
        # 历史记录滚动条
        history_scrollbar = ttk.Scrollbar(history_frame, orient="vertical", command=self.history_listbox.yview)
        history_scrollbar.grid(row=0, column=1, sticky="ns")
        self.history_listbox.configure(yscrollcommand=history_scrollbar.set)
        
        # 历史记录操作按钮
        history_btn_frame = ttk.Frame(history_frame)
        history_btn_frame.grid(row=0, column=2, padx=(10, 0), sticky="ns")
        
        clear_history_btn = ttk.Button(history_btn_frame, text="清空历史", command=self.clear_history)
        clear_history_btn.grid(row=0, column=0, pady=(0, 5))
        
        export_history_btn = ttk.Button(history_btn_frame, text="导出历史", command=self.export_history)
        export_history_btn.grid(row=1, column=0)
    
    def _create_display_section(self, parent: ttk.Frame, row: int) -> None:
        """创建显示区域"""
        display_frame = ttk.Frame(parent)
        display_frame.grid(row=row, column=0, columnspan=5, sticky="ew", pady=(0, 10))
        display_frame.columnconfigure(0, weight=1)
        
        self.display = tk.Entry(display_frame, textvariable=self.display_var, font=("Arial", 16), 
                               justify="right", state="readonly", width=25)
        self.display.grid(row=0, column=0, sticky="ew")
    
    def _create_memory_section(self, parent: ttk.Frame, row: int) -> None:
        """创建内存显示区域"""
        memory_frame = ttk.Frame(parent)
        memory_frame.grid(row=row, column=0, columnspan=5, sticky="ew", pady=(0, 10))
        
        self.memory_label = ttk.Label(memory_frame, text="内存: 0", font=("Arial", 10))
        self.memory_label.grid(row=0, column=0, sticky="w")
    
    def _create_button_section(self, parent: ttk.Frame, row: int) -> None:
        """创建按钮区域"""
        button_frame = ttk.Frame(parent)
        button_frame.grid(row=row, column=0, columnspan=5)
        
        # 内存操作按钮
        self._create_memory_buttons(button_frame, 0)
        
        # 科学计算按钮
        self._create_scientific_buttons(button_frame, 1)
        
        # 基本计算按钮
        self._create_basic_buttons(button_frame, 3)
    
    def _create_memory_buttons(self, parent: ttk.Frame, start_row: int) -> None:
        """创建内存操作按钮"""
        memory_buttons = [
            ("MC", 0, 0, self.memory_clear),
            ("MR", 0, 1, self.memory_recall),
            ("M+", 0, 2, self.memory_add),
            ("M-", 0, 3, self.memory_subtract),
            ("MS", 0, 4, self.memory_store)
        ]
        
        for text, row, col, command in memory_buttons:
            btn = ttk.Button(parent, text=text, command=command, width=8)
            btn.grid(row=start_row + row, column=col, padx=2, pady=2)
    
    def _create_scientific_buttons(self, parent: ttk.Frame, start_row: int) -> None:
        """创建科学计算按钮"""
        scientific_buttons = [
            ("sin", 0, 0, lambda: self.scientific_operation("sin")),
            ("cos", 0, 1, lambda: self.scientific_operation("cos")),
            ("tan", 0, 2, lambda: self.scientific_operation("tan")),
            ("ln", 0, 3, lambda: self.scientific_operation("log")),
            ("log", 0, 4, lambda: self.scientific_operation("log10")),
            ("x!", 1, 0, lambda: self.scientific_operation("factorial")),
            ("x²", 1, 1, lambda: self.scientific_operation("square")),
            ("√", 1, 2, lambda: self.scientific_operation("sqrt")),
            ("π", 1, 3, lambda: self.insert_constant("pi")),
            ("e", 1, 4, lambda: self.insert_constant("e"))
        ]
        
        for text, row, col, command in scientific_buttons:
            btn = ttk.Button(parent, text=text, command=command, width=8)
            btn.grid(row=start_row + row, column=col, padx=2, pady=2)
    
    def _create_basic_buttons(self, parent: ttk.Frame, start_row: int) -> None:
        """创建基本计算按钮"""
        basic_buttons = [
            ("C", 0, 0, self.clear),
            ("CE", 0, 1, self.clear_entry),
            ("⌫", 0, 2, self.backspace),
            ("÷", 0, 3, lambda: self.insert_operator("/")),
            ("%", 0, 4, lambda: self.scientific_operation("percent")),
            ("7", 1, 0, lambda: self.insert_number("7")),
            ("8", 1, 1, lambda: self.insert_number("8")),
            ("9", 1, 2, lambda: self.insert_number("9")),
            ("×", 1, 3, lambda: self.insert_operator("*")),
            ("^", 1, 4, lambda: self.insert_operator("**")),
            ("4", 2, 0, lambda: self.insert_number("4")),
            ("5", 2, 1, lambda: self.insert_number("5")),
            ("6", 2, 2, lambda: self.insert_number("6")),
            ("-", 2, 3, lambda: self.insert_operator("-")),
            ("(", 2, 4, lambda: self.insert_operator("(")),
            ("1", 3, 0, lambda: self.insert_number("1")),
            ("2", 3, 1, lambda: self.insert_number("2")),
            ("3", 3, 2, lambda: self.insert_number("3")),
            ("+", 3, 3, lambda: self.insert_operator("+")),
            (")", 3, 4, lambda: self.insert_operator(")")),
            ("±", 4, 0, self.change_sign),
            ("0", 4, 1, lambda: self.insert_number("0")),
            (".", 4, 2, lambda: self.insert_number(".")),
            ("=", 4, 3, self.calculate)
        ]
        
        for text, row, col, command in basic_buttons:
            if text == "=":
                btn = ttk.Button(parent, text=text, command=command, width=17)
                btn.grid(row=start_row + row, column=col, columnspan=2, padx=2, pady=2)
            else:
                btn = ttk.Button(parent, text=text, command=command, width=8)
                btn.grid(row=start_row + row, column=col, padx=2, pady=2)
    
    # 数字和运算符输入方法
    def insert_number(self, number: str) -> None:
        """插入数字"""
        if self.is_new_number or self.display_var.get() == "0":
            if number == ".":
                self.display_var.set("0.")
            else:
                self.display_var.set(number)
            self.is_new_number = False
        else:
            current = self.display_var.get()
            if number == "." and "." in current:
                return
            self.display_var.set(current + number)
    
    def insert_operator(self, operator: str) -> None:
        """插入运算符"""
        if not self.is_new_number:
            self.expression += self.display_var.get()
        self.expression += operator
        self.is_new_number = True
        self.display_var.set("0")
    
    def insert_constant(self, constant: str) -> None:
        """插入数学常数"""
        value = None
        if constant == "pi":
            value = self.calc.pi
        elif constant == "e":
            value = self.calc.e
        
        if value is not None:
            self.display_var.set(str(value))
            self.is_new_number = True
    
    # 科学计算方法
    def scientific_operation(self, operation: str) -> None:
        """执行科学计算操作"""
        try:
            current_value = float(self.display_var.get())
            result = None
            
            if operation == "sin":
                result = self.calc.sin(current_value)
            elif operation == "cos":
                result = self.calc.cos(current_value)
            elif operation == "tan":
                result = self.calc.tan(current_value)
            elif operation == "log":
                result = self.calc.log(current_value)
            elif operation == "log10":
                result = self.calc.log10(current_value)
            elif operation == "factorial":
                result = self.calc.factorial(current_value)
            elif operation == "square":
                result = self.calc.square(current_value)
            elif operation == "sqrt":
                result = self.calc.sqrt(current_value)
            elif operation == "percent":
                result = self.calc.percent(current_value)
            
            if result is not None:
                self.display_var.set(str(result))
                self.history_manager.add_entry(f"{operation}({current_value})", str(result))
                self.is_new_number = True
            
        except Exception as e:
            messagebox.showerror("错误", str(e))
            self.clear()
    
    # 基本操作方法
    def calculate(self) -> None:
        """计算表达式"""
        try:
            if not self.is_new_number:
                self.expression += self.display_var.get()
            
            if self.expression:
                result = self.calc.evaluate_expression(self.expression)
                
                self.history_manager.add_entry(self.expression, str(result))
                self.display_var.set(str(result))
                self.expression = ""
                self.is_new_number = True
                
        except Exception as e:
            messagebox.showerror("错误", f"计算错误: {str(e)}")
            self.clear()
    
    def clear(self) -> None:
        """清空所有"""
        self.display_var.set("0")
        self.expression = ""
        self.is_new_number = True
    
    def clear_entry(self) -> None:
        """清空当前输入"""
        self.display_var.set("0")
        self.is_new_number = True
    
    def backspace(self) -> None:
        """退格"""
        current = self.display_var.get()
        if len(current) > 1:
            self.display_var.set(current[:-1])
        else:
            self.display_var.set("0")
    
    def change_sign(self) -> None:
        """改变符号"""
        current = self.display_var.get()
        if current != "0":
            if current.startswith("-"):
                self.display_var.set(current[1:])
            else:
                self.display_var.set("-" + current)
    
    # 内存操作方法
    def memory_clear(self) -> None:
        """清空内存"""
        self.memory_manager.clear()
    
    def memory_recall(self) -> None:
        """调用内存"""
        value = self.memory_manager.recall()
        self.display_var.set(str(value))
        self.is_new_number = True
    
    def memory_add(self) -> None:
        """内存加"""
        try:
            value = float(self.display_var.get())
            self.memory_manager.add(value)
        except ValueError:
            messagebox.showerror("错误", "无效的数值")
    
    def memory_subtract(self) -> None:
        """内存减"""
        try:
            value = float(self.display_var.get())
            self.memory_manager.subtract(value)
        except ValueError:
            messagebox.showerror("错误", "无效的数值")
    
    def memory_store(self) -> None:
        """存储到内存"""
        try:
            value = float(self.display_var.get())
            self.memory_manager.store(value)
        except ValueError:
            messagebox.showerror("错误", "无效的数值")
    
    # 历史记录操作方法
    def clear_history(self) -> None:
        """清空历史记录"""
        self.history_manager.clear_history()
    
    def export_history(self) -> None:
        """导出历史记录"""
        from tkinter import filedialog
        
        filename = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
            title="导出历史记录"
        )
        
        if filename:
            if self.history_manager.export_to_text(filename):
                messagebox.showinfo("成功", "历史记录已导出")
            else:
                messagebox.showerror("错误", "导出失败")
    
    # 回调方法
    def _on_memory_change(self, value: float) -> None:
        """内存值变化回调"""
        if self.memory_label:
            formatted_value = f"{value:.10g}" if value != 0 else "0"
            self.memory_label.config(text=f"内存: {formatted_value}")
    
    def _on_history_change(self, history: list) -> None:
        """历史记录变化回调"""
        if self.history_listbox:
            # 清空列表
            self.history_listbox.delete(0, tk.END)
            
            # 添加最近的记录（倒序显示）
            recent_entries = self.history_manager.get_recent_entries(20)
            for entry in reversed(recent_entries):
                self.history_listbox.insert(tk.END, str(entry))
            
            # 滚动到最底部
            self.history_listbox.see(tk.END)
    
    # 键盘事件处理
    def _bind_keyboard_events(self) -> None:
        """绑定键盘事件"""
        self.root.bind('<Key>', self._on_key_press)
        self.root.focus_set()
    
    def _on_key_press(self, event) -> None:
        """键盘事件处理"""
        key = event.char
        
        if key.isdigit():
            self.insert_number(key)
        elif key == ".":
            self.insert_number(".")
        elif key == "+":
            self.insert_operator("+")
        elif key == "-":
            self.insert_operator("-")
        elif key == "*":
            self.insert_operator("*")
        elif key == "/":
            self.insert_operator("/")
        elif key == "=":
            self.calculate()
        elif event.keysym == "Return":
            self.calculate()
        elif event.keysym == "BackSpace":
            self.backspace()
        elif event.keysym == "Escape":
            self.clear()
        elif event.keysym == "Delete":
            self.clear_entry()
    
    def run(self) -> None:
        """启动GUI界面"""
        self.root.mainloop()


def create_calculator_app() -> CalculatorGUI:
    """
    创建计算器应用程序实例
    
    Returns:
        CalculatorGUI实例
    """
    root = tk.Tk()
    app = CalculatorGUI(root)
    return app